
/* Generated by Interface Builder */

#import "Spectro.h"
#import "SpectrumView.h"
#import "WaterfallView.h"
#import "WaterfallComputer.h"
#import "SignalProcessor.h"
#import <appkit/appkit.h>
#import <soundkit/soundkit.h>
#import <math.h>
#import <string.h>
#import <stdio.h>

int data_size,power_of_four,window_size,num_frames,total_data,s_rate,mono_file;
float f[16384],freq_max;
BOOL running_analysis = FALSE,one_time = FALSE,waterfall = FALSE;
char window_type[200];
int firstSample,sampleCount;
float ceiling,flor;

@implementation Spectro

- changeFreqMax:sender
{
    int i;
    freq_max = [[sender cellAt: 0 : 4] floatValue];
    if (freq_max>0.5*s_rate) freq_max = 0.5 * s_rate;
    for (i=1;i<5;i++) {
        [[freqRange cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
        [[freqRange2 cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
    }
    [myView setFreqRange: freq_max andAmpRange: [myView ampRange]];
    [myView clear];
    [myView placeVerticals: 0.25];
    [self calculate:nil];
    return self;
}

- selectionChanged:sender
{
    mySound = [sender sound];
    [mySound compactSamples];
    [self setup: sender];
    if ([goOnSelect state]) [self calculate:self];
    return self;
}

- setup:sender
{
    int i;
    [[soundView docView] getSelection:&firstSample size:&sampleCount];
    if ((firstSample + sampleCount)>[[[soundView docView] sound] sampleCount])	sampleCount = [[[soundView docView] sound] sampleCount] - firstSample;
    num_frames = sampleCount / [windowSize intValue] * 2 - 1;
    if (num_frames<1) num_frames = 0;
    s_rate = [mySound samplingRate];
    [numFrames setIntValue: num_frames];
    freq_max = [[freqRange cellAt: 0 : 4] floatValue];
    if (freq_max>0.5*s_rate) freq_max = 0.5 * s_rate;
    for (i=1;i<5;i++) {
        [[freqRange cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
        [[freqRange2 cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
    }
    flor = [[viewLimit cellAt: 4: 0] floatValue];
    [myView setFreqRange: freq_max andAmpRange: flor];
    [beginTime setDoubleValue: (double) firstSample / s_rate];
    [self changeTimeSetups: numFrames]; 
    return self;
}

- calculate:sender
{
//    int temp_num_frames;
//    mySound = [[soundView docView] sound];
//    [mySound compactSamples];
//    temp_num_frames = [mySound sampleCount] / [windowSize intValue] * 2 - 1;
//    num_frames = [numFrames intValue];
//    if (temp_num_frames < num_frames)	{
//        num_frames = temp_num_frames;
//	[numFrames setIntValue: num_frames];
//        [self changeTimeSetups: numFrames]; 
//    }
    one_time = TRUE;
    [self doSpectrum];
    one_time = FALSE;
    return self;
}

- knockItOff:sender
{
    one_time = FALSE;
    return self;
}

- (int) passThisToWFViewPlease:  (float *) f 	// this is sent by WaterfallComputer to draw views
{			// It's here so later we can put the computation into a different thread
			// We're faking that now by checking the stop button explicitly each time.
    NXRect buttonBounds;
    NXPoint mousePosition;
    int mouseDown,windowIsKey;
    [myWaterfallView drawNext: f];
    [[stopButton window] getMouseLocation: &mousePosition];
    [stopButton getBounds: &buttonBounds];
    PSbuttondown(&mouseDown);
//    windowIsKey = [[stopButton window] isKeyWindow];
    if ([stopButton mouse:&mousePosition inRect: &buttonBounds] && mouseDown) return 1;
    else return 0;
}


- doSpectrum
{
    float temp_f[16384];
    int i;
    float timeDelta,timeBegin;
    unsigned char *data;
    short *linear_data;
    mySound = [[soundView docView] sound];
    if (mySound) 	{
      [mySound compactSamples];
      [[soundView docView] getSelection:&firstSample size:&sampleCount];
      if ((firstSample + sampleCount)>[[[soundView docView] sound] sampleCount])	
      	sampleCount = [[[soundView docView] sound] sampleCount] - firstSample;
      data = [mySound data];
      linear_data = (short *) data;
      strcpy(window_type,[windowType stringValue]);
      flor = [[viewLimit cellAt: 4: 0] floatValue];
      ceiling = 2.0 * 65536.0 * 65536.0 * window_size;
      mono_file = 2;
      if  ([mySound channelCount]>1) 	{
        mono_file = NXRunAlertPanel("Spectro is Confused","The current sound is stereo.\
	What should I transform?","Both Mixed","Right","Left");
	printf("%i\n",mono_file);
     }
      if (num_frames>1 && one_time)	{
	for (i=0;i<data_size;i++) temp_f[i] = f[i];
	if (!myWaterfallComputer) 	{
	    myWaterfallComputer = [[WaterfallComputer allocFromZone:[self zone]] init];
	    [myWaterfallComputer setSignalProcessor: mySignalProcessor];
	    [myWaterfallComputer setApp: self];
	}
	[myWaterfallView setup: num_frames length: (int) (data_size * freq_max / s_rate)];
	if ([mySound dataFormat]==1)	
	    [myWaterfallComputer computeThisCodex: data];
	else
	    [myWaterfallComputer computeThisLinear: linear_data];
        timeDelta = ([totalSeconds floatValue] / num_frames) * (num_frames + 1) * 0.25;
        timeBegin = [beginTime floatValue];
        for (i=0;i<5;i++)	{
            [[wfTimes cellAt: 4-i : 0] setFloatValue: timeBegin];
	    timeBegin += timeDelta;
        }
	[myView clear];
	[frameSlider setFloatValue: 0.0];
         [self sliderChange: frameSlider];
	[myView placeVerticals: 0.25];
	[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
	s_rate = [mySound samplingRate];
	if (freq_max==0)  freq_max = 0.5 * s_rate;
	for (i=1;i<5;i++) {
	    [[freqRange cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
	    [[freqRange2 cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
	}
	[myView setFreqRange: freq_max andAmpRange: flor];
	[myView placeHorizontals: 0.25];
      }
      else {
	for (i=0;i<data_size;i++) temp_f[i] = f[i];
	if ([mySound dataFormat]==1)
	    for (i=0;i<window_size;i++) f[i] = (float) SNDiMulaw(data[i + firstSample]);
	else	{
		if (mono_file==2)
		    for (i=0;i<window_size;i++) f[i] = (float) linear_data[i +firstSample];
		if (mono_file==1)
		    for (i=0;i<window_size;i++) f[i] = (float) (linear_data[2*(i +firstSample)] + 
		    							linear_data[2*(i + firstSample) + 1]) * 0.5;
		if (mono_file==0)
		    for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i + firstSample) + 1];
		if (mono_file==-1)
		    for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i + firstSample)];
	}
	for (i=window_size;i<data_size;i++) f[i] = 0.0;
	[mySignalProcessor window: window_size array: f type: window_type phase: FALSE];
	[mySignalProcessor fhtRX4: power_of_four array: f];
	[mySignalProcessor logMag: data_size array: f floor: flor ceiling: ceiling];
	[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: temp_f erase: TRUE];
	[myView placeVerticals: 0.25];
	[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
	s_rate = [mySound samplingRate];
	if (freq_max==0)  freq_max = 0.5 * s_rate;
        for (i=1;i<5;i++) {
	    [[freqRange cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
	    [[freqRange2 cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
	}
	[myView setFreqRange: freq_max  andAmpRange: flor];
	[myView placeHorizontals: 0.25];
      }
    }
    return self;
}

- changeZPFactor: sender
{
    double temp;
    window_size = [windowSize intValue];
    data_size = window_size * [zpFactor floatValue];
    num_frames = [numFrames intValue];
    temp = log((double) data_size) / log(4.0);
    if (temp>7.0) temp=7.0;
    power_of_four = temp + .999;
    data_size = pow(4.0,power_of_four);
    [zpFactor setFloatValue: ((float) data_size / (float) window_size)];
    if (s_rate>0)	temp = (float) window_size / (float) s_rate * 0.5;
    [hopTime setDoubleValue: temp];
    [windowTime setDoubleValue: temp * 2.0];
    [totalSeconds setDoubleValue: temp * [numFrames doubleValue]];
    [self setup: self];
    [self calculate: self];
    return self;
}

- changeWindowSize:sender
{
    [zpFactor setIntValue: 1];
    [myView clear];
    [self setup:self];
    [self calculate:self];
    return self;
}

- changeTimeSetups: sender
{
    double temp;
    window_size = [windowSize intValue];
    data_size = window_size * [zpFactor floatValue];
    num_frames = [numFrames intValue];
    temp = log((double) data_size) / log(4.0);
    if (temp>7.0) temp=7.0;
    power_of_four = temp + .999;
    data_size = pow(4.0,power_of_four);
    [zpFactor setFloatValue: ((float) data_size / (float) window_size)];
    mySound = [[soundView docView] sound];
    s_rate = [mySound samplingRate];
    if (s_rate>0)	temp = (float) window_size / (float) s_rate* 0.5;
    [hopTime setDoubleValue: temp];
    [windowTime setDoubleValue: temp * 2.0];
    [totalSeconds setDoubleValue: temp * [numFrames doubleValue]];
    return self;
}

- changeViewLimit:sender
{
    int temp,i;
    temp = [sender intValue];
    if (temp>0) temp = -temp;
    for (i=0;i<4;i++)  [[viewLimit cellAt: i : 0] setIntValue: temp * i / 4];
    [myView clear];
    s_rate = [mySound samplingRate];
    if (freq_max==0) 	freq_max = 0.5 * s_rate;
    for (i=1;i<5;i++) {
        [[freqRange cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
        [[freqRange2 cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
    }
    [myView setFreqRange: freq_max  andAmpRange: temp];
    [self calculate:nil];
    return self;
}

- timeChange:sender
{
    float temp;
    int plot;
    temp = [sender floatValue] - [beginTime floatValue];
    plot = temp / [hopTime floatValue];
    temp = plot /  ([numFrames floatValue]);
    [frameSlider setFloatValue: temp];
    [self sliderChange: frameSlider];
    return self;
}

- frameChange:sender
{
    float temp;
    int plot;
    plot = [sender intValue];
    temp = plot /  (1.5 + [numFrames floatValue]);
    [frameSlider setFloatValue: temp];
    [self sliderChange: frameSlider];
    return self;
}

- sliderChange:sender
{
    float temp,temp_f[17000];
    int plot,k,i;
    unsigned char *data;
    short *linear_data;
    mySound = [[soundView docView] sound];
    if (mySound)	{
	[mySound compactSamples];
	[[soundView docView] getSelection:&firstSample size:&sampleCount];
	if ((firstSample + sampleCount)>[[[soundView docView] sound] sampleCount])	    sampleCount = [[[soundView docView] sound] sampleCount] - firstSample;
	data = [mySound data];
	linear_data = (short *) data;
	strcpy(window_type,[windowType stringValue]);
	flor = [[viewLimit cellAt: 4: 0] floatValue];
	ceiling = 2.0 * 65536.0 * 65536.0 * window_size;
	temp = [sender floatValue];
	plot = temp * (2.5 + [numFrames floatValue]);
	[currentTime setFloatValue: [hopTime floatValue] * plot + [beginTime floatValue]];
	[currentPlot setIntValue: plot];
	if (plot > [numFrames intValue] - 1) plot = [numFrames intValue]  - 1;
	[myWaterfallView placeTickAt: plot];
	for (i=0;i<data_size;i++) temp_f[i] = f[i];
	[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: temp_f erase: TRUE];
	k = plot * window_size * 0.5;
	if ([mySound dataFormat]==1)	
	    for (i=0;i<window_size;i++) f[i] = (float) SNDiMulaw(data[i +k + firstSample]);
    	else	{
	    if (mono_file==2)
		for (i=0;i<window_size;i++) f[i] = (float) linear_data[i +k+ firstSample];
	    if (mono_file==1)
		for (i=0;i<window_size;i++) f[i] = (float) (linear_data[2*(i +k+ firstSample)] + 
	    								linear_data[2*(i + k+ firstSample) + 1]) * 0.5;
	    if (mono_file==0)
		for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i + k+ firstSample) + 1];
	    if (mono_file==-1)
		for (i=0;i<window_size;i++) f[i] = (float) linear_data[2*(i +k+ firstSample)];
    	}
	for (i=window_size;i<data_size;i++) f[i] = 0.0;
	[mySignalProcessor window: window_size array: f type: window_type phase: FALSE];
	[mySignalProcessor fhtRX4: power_of_four array: f];
	[mySignalProcessor logMag: data_size array: f floor: flor ceiling: ceiling];
	 [myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
	[myView placeVerticals: 0.25];
	[myView drawSpectrum: (int) (data_size * freq_max / s_rate) array: f];
	s_rate = [mySound samplingRate];
        for (i=1;i<5;i++) {
	    [[freqRange cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
	    [[freqRange2 cellAt: 0 : i] setIntValue:  i * 0.25 * freq_max];
	}
	[myView setFreqRange: freq_max  andAmpRange: flor];
	[myView placeHorizontals: 0.25];
    }
    return self;
}

- running:sender
{
    double temp;
    window_size = [windowSize intValue];
    data_size = window_size * [zpFactor floatValue];
    num_frames = [numFrames intValue];
    temp = window_size / 16024.0;
    [hopTime setDoubleValue: temp];
    [windowTime setDoubleValue: temp * 2.0];
    [totalSeconds setDoubleValue: temp * [numFrames doubleValue]];
    temp = log((double) data_size) / log(4.0);
    if (temp>7.0) temp=7.0;
    power_of_four = temp + .999;
    data_size = pow(4.0,power_of_four);
    [zpFactor setFloatValue: ((float) data_size / (float) window_size)];
    if (sender==loopButton&&[loopButton state]) [myView clear];
    if ([loopButton state]) running_analysis = TRUE; else running_analysis = FALSE;
//    if (sender==oneTime) one_time = TRUE;
    if (running_analysis || one_time)	{
    	mySound = [[soundView docView] sound];
	if (!mySound) {
	    [[soundView docView] setSound: [Sound new]];
	    mySound = [[soundView docView] sound];
            [mySound setDelegate: self];
        }
	if (running_analysis)		{
				total_data = window_size;
				[mySound setDataSize: window_size
	    				dataFormat: SND_FORMAT_MULAW_8
	    				samplingRate:SND_RATE_CODEC
	    				channelCount: 1
	    				infoSize: 12];
        }
	[mySound record];
    }
    return self;
}

- didRecord:sender
{
    if (running_analysis)	{
	[self doSpectrum];
	[self running: nil];
    }
    if (one_time) {
        [soundMeter stop:self];
	one_time = FALSE;
    }
    return self;
}

- save:sender
{
    char file_name[200];
    strcpy(file_name,[fileName stringValue]);
    [[[soundView docView] sound] writeSoundfile:file_name];
    return self;
}

- zoomOut:sender
{
    [[soundView docView] setReductionFactor: [[soundView docView] reductionFactor] * 2.0];
    return self;
}

- zoomIn:sender
{
    [[soundView docView] setReductionFactor: [[soundView docView] reductionFactor] * 0.5];
    return self;
}

- showAll:sender
{
    NXRect frame;
    double num_samps;
    num_samps = [[[soundView docView] sound] sampleCount];
    [[soundView docView] setReductionFactor: 1.0];
    [[soundView docView] getVisibleRect: &frame];
    [[soundView docView] setReductionFactor: num_samps / frame.size.width];
    return self;
}

- showSelection:sender
{
    NXRect frame;
    int beg, size;
    double num_samps;
    float total_samps;
    [[soundView docView] getSelection: &beg size: &size];
    num_samps = size;
    total_samps = (float) [[[soundView docView] sound] sampleCount];
    [[soundView docView] setReductionFactor: 1.0];
    [[soundView docView] getVisibleRect: &frame];
    [[soundView docView] setReductionFactor: num_samps / frame.size.width];
    [[soundView horizScroller] setFloatValue: (float) beg / total_samps];
    [soundView display];
    return self;
}

- play:sender
{
    [[soundView docView] setDelegate: self];
    [soundView play:sender];
    return self;
}

- stop:sender
{
    [soundView stop:sender];
    [soundMeter stop:self];
    return self;
}

- record:sender
{
	[[soundView docView] setDelegate: self];
	[soundView record:sender];
    return self;
}

- willPlay:sender
{
    [soundMeter setSound: [[soundView docView] soundBeingProcessed]];
    [soundMeter run:self];
    return self;
}

- willRecord:sender
{
    [soundMeter setSound: [[soundView docView] soundBeingProcessed]];
    [soundMeter run:self];
    return self;
}

- didPlay:sender
{
    [soundMeter stop:self];
    return self;
}

- load:sender
{
    char file_name[200];
    strcpy(file_name,[fileName stringValue]);
    [mySound free];
    if (mySound = [Sound newFromSoundfile: file_name])	{
        [[soundView docView] setSound: mySound];
        [[soundView docView] setDelegate: self];
        [self setup:sender];
    }
    else	{
        [mySound free];
	NXRunAlertPanel("Spectro is Confused","I can't find that file.",NULL,NULL,"OK");
    }
    return self;
}

@end
